package ui;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.TextLayout;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

public class SplashWindow extends JFrame {

	private boolean stop;
	private MovieClip movie;
	private BufferedImage[] tetris = new BufferedImage[6];
	private BufferedImage loading = new BufferedImage(640, 160, BufferedImage.TYPE_INT_ARGB);
	private BufferedImage dot = new BufferedImage(65, 65, BufferedImage.TYPE_INT_ARGB);
	private int dots = 1;
	private Random rnd = new Random();
	private int rgb = rnd.nextInt(0x1000000);
	private volatile int currentRGB = rgb;

	private Shape sLoading, sDot;
	private Path2D pLoading, pDot;
	private BufferedImage bLoading, bDot;

	private JPanel content = new JPanel() {
		@Override
		public void paintComponent (Graphics g) {
			super.paintComponent(g);
			Graphics2D g2d = (Graphics2D) g;
			g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
			g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
			g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
			g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

			if (movie != null) {
				synchronized (movie) {
					g2d.drawImage(movie, 0, 0, null);
				}
			}
			synchronized (loading) {
				g2d.drawImage(loading, (Constants.SCREEN_SIZE.width - loading.getWidth()) / 2, (Constants.SCREEN_SIZE.height - loading.getHeight()) / 2, null);
			}
			synchronized (dot) {
				g2d.drawImage(dot, (Constants.SCREEN_SIZE.width + loading.getWidth()) / 2 - 190 + 35 * dots, (Constants.SCREEN_SIZE.height - loading.getHeight()) / 2 + 65, null);
			}
		}
	};

	private Thread thdUpdator = new Thread() {
		@Override
		public void run () {
			while (!stop) {
				try {
					Thread.sleep(5);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				content.repaint();
			}
		}
	};

	private Thread thdColor = new Thread() {
		@Override
		public void run () {
			while (!stop) {
				while (currentRGB != rgb) {
					int cr = currentRGB & 0x00ff0000;
					int cg = currentRGB & 0x0000ff00;
					int cb = currentRGB & 0x000000ff;
					int r = rgb & 0x00ff0000;
					int g = rgb & 0x0000ff00;
					int b = rgb & 0x000000ff;
					if (cr < r) {
						cr += 0x10000;
					} else if (cr > r) {
						cr -= 0x10000;
					}
					if (cg < g) {
						cg += 0x100;
					} else if (cg > g) {
						cg -= 0x100;
					}
					if (cb < b) {
						cb++;
					} else if (cb > b) {
						cb--;
					}
					currentRGB = cr | cg | cb;
					initLoading2();
					initDot2();
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				rgb = rnd.nextInt(0x1000000);
			}
		}
	};

	private Thread thdUpdator2 = new Thread() {
		@Override
		public void run () {
			while (!stop) {
				try {
					Thread.sleep(800);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				dots = dots % 4 + 1;
			}
		}
	};

	SplashWindow () {
		setUndecorated(true);
		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		setContentPane(content);
		setBounds(0, 0, Constants.SCREEN_SIZE.width, Constants.SCREEN_SIZE.height);
		setAlwaysOnTop(true);
		setBackground(new Color(0, 0, 0, 0));

		initLoading();
		initLoading2();
		initDot();
		initDot2();
		initTetris();
		initMovie();

		setVisible(true);
		thdUpdator.start();
		thdUpdator2.start();
		thdColor.start();
	}

	private void initLoading () {
		Color c = new Color(50, 20, 80, 250);
		Font f = new Font("Tahoma", Font.BOLD, 120);
		bLoading = new BufferedImage(640, 160, BufferedImage.TYPE_INT_ARGB);
		Graphics2D g = bLoading.createGraphics();
		g.setBackground(new Color(105, 155, 0, 0));
		g.clearRect(0, 0, bLoading.getWidth(), bLoading.getHeight());
		g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
		g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

		TextLayout txt = new TextLayout("Loading", f, g.getFontRenderContext());
		sLoading = txt.getOutline(g.getTransform());
		pLoading = new Path2D.Float(Path2D.WIND_EVEN_ODD);
		pLoading.append(new Rectangle(0, 0, 640, 160), false);
		FramePane.appendTextShape(pLoading, sLoading, g.getTransform(), 15, 107);

		g.setColor(c);
		g.translate(15, 107);
		g.fill(sLoading);

		bLoading.flush();
		g.dispose();
		bLoading = FramePane.blur(bLoading, 15);
	}

	private void initLoading2 () {
		synchronized (loading) {
			Graphics2D g = loading.createGraphics();
			g.setBackground(new Color(0, 0, 0, 0));
			g.clearRect(0, 0, loading.getWidth(), loading.getHeight());
			g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
			g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
			g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
			g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

			g.translate(15, 107);
			g.setColor(new Color(currentRGB >>> 16 & 0xff, currentRGB >>> 8 & 0xff, currentRGB & 0xff, 230));
			g.fill(sLoading);
			g.translate(-15, -107);
			g.setClip(pLoading);
			g.drawImage(bLoading, 10, 10, null);
			g.setClip(pLoading);
			g.drawImage(bLoading, 0, 0, null);

			loading.flush();
			g.dispose();
		}
	}

	private void initDot () {
		Color c = new Color(50, 20, 80, 250);
		Font f = new Font("Tahoma", Font.BOLD, 120);
		bDot = new BufferedImage(65, 65, BufferedImage.TYPE_INT_ARGB);
		Graphics2D g = bDot.createGraphics();
		g.setBackground(new Color(105, 155, 0, 0));
		g.clearRect(0, 0, bDot.getWidth(), bDot.getHeight());
		g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
		g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

		TextLayout txt = new TextLayout(".", f, g.getFontRenderContext());
		sDot = txt.getOutline(g.getTransform());
		pDot = new Path2D.Float(Path2D.WIND_EVEN_ODD);
		pDot.append(new Rectangle(0, 0, 65, 65), false);
		FramePane.appendTextShape(pDot, sDot, g.getTransform(), 15, 40);

		g.setColor(c);
		g.translate(15, 40);
		g.fill(sDot);

		bDot.flush();
		g.dispose();
		bDot = FramePane.blur(bDot, 15);
	}

	private void initDot2 () {
		synchronized (dot) {
			Graphics2D g = dot.createGraphics();
			g.setBackground(new Color(0, 0, 0, 0));
			g.clearRect(0, 0, dot.getWidth(), dot.getHeight());
			g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
			g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
			g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
			g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

			g.translate(15, 40);
			g.setColor(new Color(currentRGB >>> 16 & 0xff, currentRGB >>> 8 & 0xff, currentRGB & 0xff, 230));
			g.fill(sDot);
			g.translate(-15, -40);
			g.setClip(pDot);
			g.drawImage(bDot, 10, 10, null);
			g.setClip(pDot);
			g.drawImage(bDot, 0, 0, null);

			dot.flush();
			g.dispose();
		}
	}

	private void initTetris () {
		char[] tr = "TETRIS".toCharArray();
		Color c = new Color(180, 200, 255, 200);
		Font f = new Font("Tahoma", Font.BOLD, 36);
		for (int i = 0; i < tetris.length; i++) {
			BufferedImage blured = new BufferedImage(60, 65, BufferedImage.TYPE_INT_ARGB);
			Graphics2D g = blured.createGraphics();
			g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
			g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
			g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
			g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

			TextLayout txt = new TextLayout(String.valueOf(tr[i]), f, g.getFontRenderContext());
			Shape s = txt.getOutline(g.getTransform());
			Path2D path = new Path2D.Float(Path2D.WIND_EVEN_ODD);
			path.append(new Rectangle(0, 0, 60, 65), false);
			FramePane.appendTextShape(path, s, g.getTransform(), 15, 45);

			g.setColor(c);
			g.translate(15, 45);
			g.fill(s);

			blured.flush();
			g.dispose();
			blured = FramePane.blur(blured, 15);

			tetris[i] = new BufferedImage(60, 65, BufferedImage.TYPE_INT_ARGB);
			g = tetris[i].createGraphics();
			g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
			g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
			g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
			g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

			g.translate(15, 45);
			g.setColor(new Color(255, 250, 255, 60));
			g.fill(s);
			g.translate(-15, -45);
			g.setClip(path);
			g.drawImage(blured, 0, 0, null);

			tetris[i].flush();
			g.dispose();
		}
	}

	private void initMovie () {
		movie = new MovieClip(0, 0, Constants.SCREEN_SIZE.width, Constants.SCREEN_SIZE.height, BufferedImage.TYPE_INT_ARGB);
		int num = 57 + rnd.nextInt(3);
		for (int i = 0; i < num; i++) {
			movie.add(tetris[rnd.nextInt(6)]);
			movie.setRandomImageOptions(i, tetris);
			movie.setStartPoint(i, new Point2D.Double((Constants.SCREEN_SIZE.width - 80) * Math.random(), Constants.SCREEN_SIZE.height * Math.random()));
			movie.setStartRotation(i, Math.random() * 6.28);
			movie.setStartScale(i, 0.8 + Math.random() * 0.5);
			double[] speed = new double[50];
			double[] rotateSpeed = new double[50];
			double baseSpeed = Constants.SCREEN_SIZE.height * (0.3 + 0.3 * Math.random()) / 10000;
			double baseRotateSpeed = 6.28 / 6000;
			for (int j = 0; j < speed.length; j += 2) {
				speed[j] = (0.3 + Math.random()) * baseSpeed;
				speed[j + 1] = 1800 * (1.8 + Math.random());
			}
			for (int j = 0; j < rotateSpeed.length; j += 2) {
				rotateSpeed[j] = (0.2 + Math.random()) * baseRotateSpeed;
				rotateSpeed[j + 1] = 1800 * (1.8 + Math.random());
			}
			movie.setSpeed(i, speed);
			movie.setRotationSpeed(i, rotateSpeed);
		}
		movie.start(-1);	// infinite loop
	}

	void close () {
		dispose();
		movie.stop();
		stop = true;
	}

}
